package ru.ifmo.croak.impl.remoting.post.team2.client;

import ru.ifmo.croak.api.Message;
import ru.ifmo.croak.util.CroakFactory;

import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.UUID;
import java.util.concurrent.*;
import java.util.logging.Logger;

/**
 * Created by IntelliJ IDEA.
 * User: yevgeniy
 * Date: 5/23/11
 * Time: 2:22 AM
 * To change this template use File | Settings | File Templates.
 */
public class MessageSender implements Runnable {
    private ConcurrentHashMap<UUID, Message> sendBuffer = new ConcurrentHashMap<UUID, Message>();
    private static final long DELAY = 3000;
    CopyOnWriteArrayList<Socket> sockets = new CopyOnWriteArrayList();
    String name;
    Logger log;
    public MessageSender(String postServiceName) {
        String hostsInOneString = CroakFactory.getInstance().getProperty(postServiceName+".post.remote");
        String[] hosts;
        hosts = hostsInOneString.split(",");
        name = postServiceName+"_MessageSender";
        log = Logger.getLogger(name);
        for (String hostName : hosts) {
            String [] address = hostName.split(":");
            int port = Integer.parseInt(address[1]);
            try {
                sockets.add(new Socket(address[0], port));
            } catch (UnknownHostException e) {
                log.info("Unknown host " + hostName);
            } catch (IOException e) {
                e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
            }
        }
    }

    public void start() {
        ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
        ScheduledFuture<?> scheduled = scheduler.scheduleWithFixedDelay(new RealMessageSender(sendBuffer, sockets), 0, DELAY, TimeUnit.MILLISECONDS);
        for (Socket socket : sockets) {
            Thread waitThread = new Thread(new RealMessageWaiter(sendBuffer, socket));
        }

    }

    public void run() {
//        try {
//            while (true) {
//                while(sendBuffer.isEmpty())
//                    wait();
//                for (String hostName : hosts) {
//                    String [] address = hostName.split(":");
//                    int port = Integer.parseInt(address[1]);
//                    Socket s = new Socket(address[0], port);
//                    String fullMessage = message.getId().toString()+'\n'+message.getTime()+'\n'+message.getAuthor()+'\n';
//                    fullMessage += message.getText();
//                    fullMessage = fullMessage.length()+"$"+fullMessage;
//                    s.getOutputStream().write(fullMessage.getBytes());
//
//                    //Fix Me : waiting answer from server!!! after say to dumper to delete message
//                }
//            }
//        } catch (InterruptedException e) {
//            log.info(name + " service is fall down cause of InterruptedException");
//        } catch (IOException e) {
//            log.info(name + " service is fall down cause of IOException");
//        }
    }

    private class RealMessageSender implements Runnable {
        ConcurrentHashMap<UUID, Message> sendBuffer;
        CopyOnWriteArrayList<Socket> sockets;

        public RealMessageSender (ConcurrentHashMap<UUID, Message> sendBuffer, CopyOnWriteArrayList<Socket> sockets) {
            this.sendBuffer = sendBuffer;
            this.sockets = sockets;
        }

        public void run() {
            try {
                while(sendBuffer.isEmpty())
                    MessageSender.this.wait();
                Message[] messages = new Message[sendBuffer.size()];
                messages = sendBuffer.values().toArray(messages);
                for (Message message : messages) {
                    for (Socket socket : sockets) {
                        String fullMessage = message.getId().toString()+'\n'+message.getTime()+'\n'+message.getAuthor()+'\n';
                        fullMessage += message.getText();
                        fullMessage = fullMessage.length()+"$"+fullMessage;
                        socket.getOutputStream().write(fullMessage.getBytes());

                        //Fix Me : waiting answer from server!!! after say to dumper to delete message
                    }
                }
            } catch (InterruptedException interruptedException) {
            } catch (IOException iOException) {
            }
        }
    }

    private class RealMessageWaiter implements Runnable {
        ConcurrentHashMap<UUID, Message> sendBuffer;
        Socket socket;

        public RealMessageWaiter (ConcurrentHashMap<UUID, Message> sendBuffer, Socket socket) {
            this.sendBuffer = sendBuffer;
            this.socket = socket;
        }

        public void run() {
            try {
                InputStream inputStream = socket.getInputStream();
                int c;
                while (true) {
                    String line = "";
                    while ((c=inputStream.read()) != '$') {
                        line += (char)c;
                    }
                    UUID id = UUID.fromString(line);
                    sendBuffer.remove(id);
                }
            } catch (IOException e) {
                e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
            }

        }
    }

    public synchronized void addMessage(Message message) {
        sendBuffer.put(message.getId(), message);
        notifyAll();
    }
}
